package org.hzero.business;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @ClassName: OrderStatusUtil
 * @Description: 校验单据的状态
 * @author: tianhao.luo@hand-china.com
 * @date: 2020/9/24 1:38
 */
public final class KnifeCheckStatusUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(KnifeCheckStatusUtil.class);

    /**
     * 校验list中所有对象指定field属性的值在statusArray中
     *
     * @param list         被校验的list
     * @param statusArray  允许通过的状态
     * @param errorMessage 错误信息提示
     * @param fieldName    状态属性字段
     * @param <T>          占位符
     */
    public static <T> void checkList(List<T> list, String fieldName, String errorMessage, String... statusArray) {
        if (!CollectionUtils.isEmpty(list)) {
            Set<String> allowStatusSet = new HashSet<>(Arrays.asList(statusArray));
            //对list进行遍历校验状态
            for (T item : list) {
                checkOne(item, fieldName, errorMessage, allowStatusSet);
            }
        }
    }

    /**
     * 校验一个对象中指定statusFieldName的属性是否包含在allowStatusSet中
     *
     * @param item            对象
     * @param statusFieldName 状态属性字段名
     * @param errorMessage    报错消息
     * @param allowStatusSet  允许的状态
     * @param <T>             占位符
     */
    private static <T> void checkOne(T item, String statusFieldName, String errorMessage, Set<String> allowStatusSet) {
        Class<?> aClass = item.getClass();
        String itemStatus = null;
        Field haveFieldFlag = null;
        haveFieldFlag = getExistField(aClass, statusFieldName);
        Assert.notNull(haveFieldFlag, "对象没有" + statusFieldName + "属性");
        if (!haveFieldFlag.isAccessible()) {
            haveFieldFlag.setAccessible(true);
        }
        try {
            itemStatus = (String) haveFieldFlag.get(item);
        } catch (IllegalAccessException e) {
            LOGGER.error("无法从对象中获取状态字段的值！");
        }
        Assert.isTrue(allowStatusSet.contains(itemStatus), errorMessage);
    }


    /**
     * 校验一个对象中指定statusFieldName的属性是否包含在allowStatusSet中
     *
     * @param item            对象
     * @param statusFieldName 状态属性字段名
     * @param errorMessage    报错消息
     * @param allowStatusSet  允许的状态
     * @param <T>             占位符
     * @return 状态属性
     */
    private static <T> Field checkOneAndGetStatusField(T item, String statusFieldName, String errorMessage, Set<String> allowStatusSet) {
        Class<?> aClass = item.getClass();
        String itemStatus = null;
        Field haveFieldFlag = null;
        haveFieldFlag = getExistField(aClass, statusFieldName);
        Assert.notNull(haveFieldFlag, "对象没有" + statusFieldName + "属性");
        if (!haveFieldFlag.isAccessible()) {
            haveFieldFlag.setAccessible(true);
        }
        try {
            itemStatus = (String) haveFieldFlag.get(item);
        } catch (IllegalAccessException e) {
            LOGGER.error("无法从对象中获取状态字段的值！");
        }
        Assert.isTrue(allowStatusSet.contains(itemStatus), errorMessage);
        return haveFieldFlag;
    }

    /**
     * 校验单头中指定field属性的值在statusArray中
     *
     * @param orderHeader  被校验的单头
     * @param statusArray  想要校验的状态
     * @param fieldName    状态属性字段
     * @param errorMessage 报错消息编码
     * @param <T>          占位符
     */
    public static <T> void checkOne(T orderHeader, String fieldName, String errorMessage, String... statusArray) {
        Assert.notNull(orderHeader, "校验的单据不能为空！");
        Assert.isTrue(!StringUtils.isEmpty(fieldName), "状态属性字段不能为空！");
        Set<String> allowStatusSet = new HashSet<>(Arrays.asList(statusArray));
        Assert.isTrue(!CollectionUtils.isEmpty(allowStatusSet), "校验状态的对象不能为空！");
        checkOne(orderHeader, fieldName, errorMessage, allowStatusSet);
    }


    /**
     * 校验单头中指定field属性的值在statusArray中
     *
     * @param orderHeader  被校验的单头
     * @param statusArray  想要校验的状态
     * @param fieldName    状态属性字段
     * @param errorMessage 报错消息编码
     * @param <T>          占位符
     * @return 状态属性
     */
    public static <T> Field checkOneAndGetStatusField(T orderHeader, String fieldName, String errorMessage, String... statusArray) {
        Assert.notNull(orderHeader, "校验的单据不能为空！");
        Assert.isTrue(!StringUtils.isEmpty(fieldName), "状态属性字段不能为空！");
        Set<String> allowStatusSet = new HashSet<>(Arrays.asList(statusArray));
        Assert.isTrue(!CollectionUtils.isEmpty(allowStatusSet), "校验状态的对象不能为空！");
        return checkOneAndGetStatusField(orderHeader, fieldName, errorMessage, allowStatusSet);
    }

    /**
     * 从下至上递归查询属性
     *
     * @param orderClass 子class
     * @param fieldName  属性名
     * @param <T>        占位符
     * @return 属性
     */
    public static <T> Field getExistField(Class<T> orderClass, String fieldName) {
        // 默认为不存在fieldName的属性
        Field returnField = null;
        //拿到当前类的所有属性
        Field[] fields = orderClass.getDeclaredFields();
        //遍历所有，并且找出同名的属性
        for (Field field :
                fields) {
            if (field.getName().equals(fieldName)) {
                returnField = field;
            }
        }
        //如果没有找到该属性，去父类里找
        if (returnField == null) {
            Class<? super T> superclass = orderClass.getSuperclass();
            if (null != superclass) {
                return getExistField(superclass, fieldName);
            } else {
                LOGGER.error("对象没有{}属性", fieldName);
            }
        }
        return returnField;
    }
}
